﻿
// mfcclientDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "mfcclient.h"
#include "mfcclientDlg.h"
#include "afxdialogex.h"
#include "Login.h"
#include <windows.h>
#include <vector>
#include <map>
#include <io.h>    
#include <fcntl.h>  
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


SOCKET s;
map<CString, int> mapUserList;
int userID;
CString username;
FILE* fp;

CmfcclientDlg::CmfcclientDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CmfcclientDlg::IDD, pParent)
	, m_chatlog(_T(""))
	, m_sendchat(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CmfcclientDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST1, m_list);
	DDX_Text(pDX, IDC_EDIT1, m_chatlog);
	DDX_Text(pDX, IDC_EDIT2, m_sendchat);
}

BEGIN_MESSAGE_MAP(CmfcclientDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_LBN_DBLCLK(IDC_LIST1, &CmfcclientDlg::OnLbnDblclkList1)
	ON_WM_DROPFILES()
	ON_BN_CLICKED(IDOK, &CmfcclientDlg::OnBnClickedOk)
END_MESSAGE_MAP()


// CmfcclientDlg 消息处理程序
void InitConsoleWindow()    
{    
    AllocConsole();    
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);    
    int hCrt = _open_osfhandle((long)handle,_O_TEXT);    
    FILE * hf = _fdopen( hCrt, "w" );    
    *stdout = *hf;    
}  

BOOL CmfcclientDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	s = socket(AF_INET, SOCK_STREAM, 0);
	sockInit();
	CLogin login_Dialog;
	CString str_User;
	CString str_Password;
	InitConsoleWindow();//启动命令行调试窗口
	int nReturn = login_Dialog.DoModal();
	if (nReturn == IDOK) {
			//CWnd* login_Hwnd = GetDlgItem(IDD_LOGIN);
		str_User = login_Dialog.m_user;
		//str_Password = login_Dialog.m_password;
	}
	m_list.AddString(str_User);
	m_list.AddString("all");
	mapUserList.insert(pair<CString, int>("all",0));
    WSAAsyncSelect(s, m_hWnd, UM_SOCK, FD_READ|FD_CLOSE);
	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CmfcclientDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CmfcclientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}





void CmfcclientDlg::OnLbnDblclkList1()
{
	// TODO: 在此添加控件通知处理程序代码
	int cursel=m_list.GetCurSel();//获取要发送的用户名
	if (cursel==0) return;
	m_list.GetText(cursel,username);
	userID=mapUserList.find(username)->second;
	//printf("%d\n",userID);
	UpdateData(TRUE);
	m_sendchat=">"+username+":";
	UpdateData(FALSE);
}

LRESULT CmfcclientDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	// TODO: Add your specialized code here and/or call the base class
	SOCKET s,ns;
	int wmEvent;
	int len;
	struct sockaddr_in remote;
	TCHAR buf[48];
	TCHAR buffer[1012];
	unsigned long retval;
	CString recvbuf;
	vector <CString> que;
	vector<CString>::iterator it;
	char type;
	char str[1000];
	istringstream iss;
	string userName,userID,fileName;
	CString cuserName,fileLog;
	int pos;
	switch (message) {
	case UM_SOCK:
		s = (SOCKET)wParam;
		wmEvent = LOWORD(lParam);
		switch (wmEvent) {
		case FD_READ:
			//wsprintf(buf, _T("recvfrom()  %d\n"), s);
			//MessageBox(buf, _T(""), MB_OK);
			len = sizeof(buffer);
			len = recv(s, (char*)buffer, len, 0);
			if (len <= 0) {
				retval = WSAGetLastError();
				wsprintf(buf, _T("recvfrom() failed %u\n"), retval);
				MessageBox(buf, _T("Receiving Error"), MB_OK);
				break;
			}
			//cout << buffer;
			type=((PDU*)buffer)->type;
			switch(type){
					case USER_LIST:
						GetDataFromPDU((PDU*)buffer,str);
						//iss.str(str);
						printf("%s\n",str);
						//iss>>userName>>userID;
						//cuserName=userName.c_str();
						cuserName=str;
						//mapUserList.insert(pair<CString, int>(cuserName,atoi(userID.c_str())));
						mapUserList.insert(pair<CString, int>(cuserName,((PDU*)buffer)->flag));
						m_list.AddString(cuserName);
						break;
					case CHAT_DATA:
						GetDataFromPDU((PDU*)buffer,str);
						//cout<<str;
						UpdateData(TRUE);
						m_chatlog=m_chatlog+str+"\r\n";
						UpdateData(FALSE);
						break;
					case CMD_FILE:
						GetDataFromPDU((PDU*)buffer,str);
						fileName=str;
						UpdateData(TRUE);
						m_chatlog=m_chatlog+str+"\r\n";
						UpdateData(FALSE);
						pos=fileName.find_first_of(":");
						fileName=fileName.substr(pos + 1);
						fp=fopen(fileName.c_str(),"wb+");
						break;
					case FILE_DATA:
						GetDataFromPDU((PDU*)buffer,str);
						printf("recvdatalen %d\n",((PDU*)buffer)->length);
						fwrite(str, sizeof(char), ((PDU*)buffer)->length, fp);
						UpdateData(TRUE);
						if(((PDU*)buffer)->length<BUFSIZE){
							m_chatlog=m_chatlog+"recv file finish";
							fclose(fp);
						}
						UpdateData(FALSE);
						break;
			}
			break;
		case FD_CLOSE:
			MessageBox(_T("socket closed\n"), NULL, MB_OK);
			closesocket(s);
			WSACleanup();
			exit(0);
			break;
		default:
			break;
		}
		break;
	default:
		return CDialog::WindowProc(message, wParam, lParam);
	}
	return 0;
}
void CmfcclientDlg::OnDropFiles(HDROP hDropInfo)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	int DropCount=DragQueryFile(hDropInfo,-1,NULL,0);//取得被拖动文件的数目
	PDU sendbuf;
	int retval,len;
	char buffer[1100],str[1000];
    for(int i=0;i< DropCount;i++)  
    {  
        CHAR wcStr[MAX_PATH];  
        DragQueryFile(hDropInfo,i,wcStr,MAX_PATH);//获得拖曳的第i个文件的文件名 
		cout << wcStr;
		string path=wcStr;
		int pos = path.find_last_of('\\');
		string filename(path.substr(pos + 1));
		UpdateData(TRUE);
		m_chatlog+=">"+username+" "+filename.c_str()+" begin";
		SetDataPacket(&sendbuf, CMD_FILE,userID,(char*)filename.c_str(),strlen(filename.c_str())+1);
		Buffer(&sendbuf,buffer);
		send(s, buffer, 12+strlen(filename.c_str())+1, 0);
		FILE* fp;
		char buf[BUFSIZE];
		memset(buffer,0,sizeof(buffer));
		fp=fopen(wcStr,"rb");
		if (fp == NULL)  
        {  
            printf("File Not Found!\n");  
        }  
        else  
        {   
            int file_block_length = 0;  
            while( (file_block_length = fread(buf, sizeof(char), BUFSIZE, fp)) > 0)  
            {  
                printf("file_block_length = %d\n", file_block_length);  
				SetDataPacket(&sendbuf, FILE_DATA,userID,buf,file_block_length);
				Buffer(&sendbuf,buffer);
				GetDataFromPDU((PDU*)buffer,str);
				//printf("getdata %s\n", str);
				int templen = 0;
				while (templen < (12+file_block_length)){
					retval=send(s, buffer+templen, 12+file_block_length-templen, 0); 
					printf("%d\n",retval);
					if (retval < 0){
						retval = WSAGetLastError();
						if (retval == WSAEWOULDBLOCK){
							continue;
						}
						printf("%d\n", retval);
					}  
					templen += retval;
                }  
            }  
            fclose(fp);  
			m_chatlog=m_chatlog+"File Transfer Finished!\r\n";  
        }    
		UpdateData(FALSE);
    }   
    DragFinish(hDropInfo);  //拖放结束后,释放内存  
	CDialogEx::OnDropFiles(hDropInfo);
}

void sockInit()
{
	struct sockaddr_in remote;
	WSAData wsa;
	char str[25];
	WSAStartup(0x101, &wsa);
	if (s == INVALID_SOCKET) {
		MessageBox(NULL,"socket() failed\n",NULL,MB_OK);
		return;
	}
	remote.sin_family = AF_INET;
	remote.sin_addr.S_un.S_addr =htonl(INADDR_LOOPBACK);
	remote.sin_port = htons(0x1234);
	int retval = connect(s, (sockaddr *)&remote, sizeof(remote));
	if (retval != 0){
			retval = WSAGetLastError();
			itoa(retval, str, 10);
			MessageBox(NULL,"connect error\n", str, MB_OK);
			exit(1);
		}		
}

void CmfcclientDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	PDU sendbuf;
	char buffer[1100];
	CString tempEdit;
	tempEdit=">"+username+":";
	UpdateData(TRUE);
	m_chatlog=m_chatlog+m_sendchat+"\r\n";
	m_sendchat.Delete(0,tempEdit.GetLength());
	SetDataPacket(&sendbuf, CHAT_DATA,userID,m_sendchat.GetBuffer(),strlen(m_sendchat.GetBuffer())+1);
	Buffer(&sendbuf,buffer);
	send(s, buffer, 12+strlen(m_sendchat.GetBuffer())+1, 0);
	m_sendchat=">"+username+":";
	UpdateData(FALSE);
}
